﻿#include "MarketDataStream.h"
#include "Tools.h"
#include "FileOperator.h"
#include <iostream>
#ifdef __linux__
#include <cstring>
#endif
#include <QFile>
#include "CTPTime.h"
#include "OptionManager.h"

MDIO::KItem::KItem()
{
	m_kItemDir = OptionManager::Instance().GetBaseKItemDir() + '/';
}

MDIO::KItem::~KItem()
{
}

bool MDIO::KItem::GetLastKItem(const std::string &pSymbolName, const tm &curDay, MData::KLineItem &outItem)
{
	bool result = false;
	tm lastDay = CTPTm::GetMarketDay(curDay);
	memset(&outItem, 0, sizeof(MData::KLineItem));
	for (int i = 0; i < 15; ++i)
	{
		const std::string pdayStr = Tools::DateToStr(lastDay);
		std::string filePath = m_kItemDir + pdayStr + '/' + pSymbolName + ".klin";
		FileOperator::FileBin symbolFile(filePath.c_str());
		bool suc = FileOperator::ReadLastKLine(symbolFile.FileInstance(), outItem);
		if (suc)
		{
			result = true;
			break;
		}
		lastDay = Tools::AddDays(lastDay, -1);
	}
	return result;
}

void MDIO::KItem::ReverseReadKItems(const std::string &pSymbolName, time_t curDateTimeStamp, std::vector<MData::KLineItem> &outItems, int pN)
{
	tm lasttm = Tools::GetDateTimeFrmStamp(curDateTimeStamp);
	std::string dbDir = m_kItemDir;
	outItems.reserve(pN);

	int kmaIndex = 0;
	for (int i = 0; i < 10; ++i)
	{
		if (kmaIndex >= pN)
		{
			break;
		}
		const std::string pdayStr = CTPTm::GetMarketDayStr(lasttm);
		lasttm = Tools::AddDays(lasttm, -1);
		std::string filePath = dbDir + pdayStr + '/' + pSymbolName + ".klin";
		// 将所有K线读取出来
		FileOperator::FileBin symbolFile(filePath.c_str(), "rb");
		if (symbolFile.FileInstance() == nullptr)
		{
			continue;
		}
		fseek(symbolFile.FileInstance(), 0, SEEK_END);
		int len = ftell(symbolFile.FileInstance());
		int ksize = len / sizeof(MData::KLineItem);
		if (ksize <= 0)
		{
			continue;
		}
		fseek(symbolFile.FileInstance(), 0, SEEK_SET);
		MData::KLineItem *tmpItems = new MData::KLineItem[ksize];
		fread(tmpItems, len, 1, symbolFile.FileInstance());
		for (int tmpIndex = ksize - 1; tmpIndex >= 0; --tmpIndex)
		{
			if (kmaIndex >= pN)
			{
				break;
			}
			//std::string curDateTimeStr = Tools::DateTimeStamp2Str(curDateTimeStamp);
			//std::string kDateTimeStr = Tools::DateTimeStamp2Str(tmpItems[tmpIndex].UpdateTime);
			if (tmpItems[tmpIndex].UpdateTime > curDateTimeStamp)
			{
				continue;
			}
			outItems.emplace_back(tmpItems[tmpIndex]);
			++kmaIndex;
		}
		delete[]tmpItems;
	}
}

void MDIO::KItem::AppendKItem(const std::string &pSymbolName, const MData::KLineItem &pItem)
{
	tm itemTime = Tools::GetDateTimeFrmStamp(pItem.UpdateTime);
	const std::string pdayStr = CTPTm::GetMarketDayStr(itemTime);
	OptionManager::Instance().MakeSureDir(m_kItemDir + pdayStr);
	std::string filePath = m_kItemDir + pdayStr + '/' + pSymbolName + ".klin";
	FileOperator::FileBin symbolFile(filePath.c_str());
	FileOperator::AppendKLine(symbolFile.FileInstance(), pItem);
}

bool MDIO::KItem::UpdateLastKItem(const std::string &pSymbolName, const MData::KLineItem &pItem)
{
	tm itemTime = Tools::GetDateTimeFrmStamp(pItem.UpdateTime);
	const std::string pdayStr = CTPTm::GetMarketDayStr(itemTime);
	OptionManager::Instance().MakeSureDir(m_kItemDir + pdayStr);
	std::string filePath = m_kItemDir + pdayStr + '/' + pSymbolName + ".klin";
	// 首先读取所有的K线
	std::deque<MData::KLineItem> allKItems;
	ReadKItemFile(filePath, allKItems);
	if (allKItems.empty())
	{
		return false;
	}
	// 更新最后一根K线
	MData::KLineItem &laskKItem = allKItems.back();
	laskKItem.High = std::max(laskKItem.High, pItem.High);
	laskKItem.Low = std::min(laskKItem.Low, pItem.Low);
	laskKItem.Close = pItem.Close;
	laskKItem.CloseTime = pItem.CloseTime;
	// 输出K线
	FileOperator::FileBin symbolFile(filePath.c_str(), "wb");
	for (std::deque<MData::KLineItem>::iterator it = allKItems.begin(); it != allKItems.end(); ++it)
	{
		bool suc = FileOperator::AppendKLine(symbolFile.FileInstance(), *it);
		if (!suc)
		{
			return false;
		}
	}
	return true;
}

void MDIO::KItem::ReadKItemFile(const std::string &pdbFile, std::deque<MData::KLineItem> &outKItems)
{
	FileOperator::FileBin fileDb(pdbFile.c_str(), "rb");
	if (fileDb.FileInstance() == nullptr)
	{
		return;
	}
	fseek(fileDb.FileInstance(), 0L, SEEK_END);
	int len = ftell(fileDb.FileInstance());
	rewind(fileDb.FileInstance());
	int ksz = len / sizeof(MData::KLineItem);
	for (int i = 0; i < ksz; ++i)
	{
		outKItems.emplace_back(MData::KLineItem());
		fread(&outKItems.back(), sizeof(MData::KLineItem), 1, fileDb.FileInstance());
	}
}

void MDIO::KItem::ReadKItemsInDays(const std::string &pSymbolName, time_t beginDay, time_t endDay, std::deque<MData::KLineItem> &outKItems)
{
	std::vector<std::string> dbNames;
	CTPTm::DateRangeToStringList(beginDay, endDay, dbNames);
	// 遍历所有的数据库
	for (std::vector<std::string>::iterator it = dbNames.begin();
		it != dbNames.end(); ++it)
	{
		std::string dbtabFile = GetKItemDir() + *it + '/' + pSymbolName + ".klin";
		ReadKItemFile(dbtabFile, outKItems);
	}
}

void MDIO::KItem::ReadKItemsInTimes(const std::string &pSymbolName, time_t beginTime, time_t endTime, std::deque<MData::KLineItem> &outKItems)
{
	std::deque<MData::KLineItem> nKItems;
	ReadKItemsInDays(pSymbolName, beginTime, endTime, nKItems);
	for (std::deque<MData::KLineItem>::iterator it = nKItems.begin(); it != nKItems.end(); ++it)
	{
		if (it->UpdateTime < beginTime)
		{
			continue;
		}
		if (it->UpdateTime > endTime)
		{
			break;
		}
		outKItems.emplace_back(*it);
	}
}

MDIO::TMPKItem::TMPKItem()
{
	m_tmpKItemDir = OptionManager::Instance().GetGenDir() + "/TMPKItems/";
}

void MDIO::TMPKItem::GetKItem(const std::string &pSymbolName, MData::KLineItem &outItem)
{
	memset(&outItem, 0, sizeof(MData::KLineItem));
	outItem.UpdateTime = 0;
	std::string filePath = m_tmpKItemDir + pSymbolName + ".klin";
	FileOperator::FileBin symbolFile(filePath.c_str(), "rb");
	FileOperator::ReadLastKLine(symbolFile.FileInstance(), outItem);
}

void MDIO::TMPKItem::UpdateKItem(const std::string &pSymbolName, const MData::KLineItem &pItem)
{
	std::string filePath = m_tmpKItemDir + pSymbolName + ".klin";
	FileOperator::FileBin symbolFile(filePath.c_str(), "wb");
	FileOperator::AppendKLine(symbolFile.FileInstance(), pItem);
}

void MDIO::TMPKItem::RemoveTmpKItem(const std::string &pSymbolName)
{
	std::string filePath = m_tmpKItemDir + pSymbolName + ".klin";
	QString qFilePath = QString::fromLocal8Bit(filePath.c_str());
	QFile kFile(qFilePath);
	kFile.remove();
}

MDIO::Price::Price()
{
	m_priceDir = OptionManager::Instance().GetMarketDataDir() + '/';
}

void MDIO::Price::AppPrice(const std::string &pToday, const std::string &pSymbol, const MData::PriceItem &pItem)
{
	std::string replayDir = GetPriceDir() + pToday;
	OptionManager::Instance().MakeSureDir(replayDir);
	std::string filePath = replayDir + '/' + pSymbol + ".pce";
	FileOperator::FileBin symbolFile(filePath.c_str());
	FileOperator::AppendPrice(symbolFile.FileInstance(), pItem);
}

void MDIO::Price::GetAllPrice(const std::string &pToday, const std::string &pSymbol, std::deque<MData::PriceItem> &outPrices)
{
	std::string replayDir = GetPriceDir() + pToday;
	OptionManager::Instance().MakeSureDir(replayDir);
	std::string filePath = replayDir + '/' + pSymbol + ".pce";
	FileOperator::FileBin symbolFile(filePath.c_str(), "rb");

	if (symbolFile.FileInstance() == nullptr)
	{
		return;
	}
	fseek(symbolFile.FileInstance(), 0L, SEEK_END);
	int len = ftell(symbolFile.FileInstance());
	rewind(symbolFile.FileInstance());
	int ksz = len / sizeof(MData::PriceItem);
	for (int i = 0; i < ksz; ++i)
	{
		outPrices.emplace_back(MData::PriceItem());
		fread(&outPrices.back(), sizeof(MData::PriceItem), 1, symbolFile.FileInstance());
	}
}

MDIO::ShareMemoryGard::ShareMemoryGard(QSharedMemory &pMemory)
	:m_memory(pMemory)
{
	m_memory.lock();
}

MDIO::ShareMemoryGard::~ShareMemoryGard()
{
	m_memory.unlock();
}

MDIO::SystemSemaphoreGard::SystemSemaphoreGard(QSystemSemaphore &pSystemSemaphore)
	:m_systemSemaphore(pSystemSemaphore)
{
	m_systemSemaphore.acquire();
}

MDIO::SystemSemaphoreGard::~SystemSemaphoreGard()
{
	m_systemSemaphore.release();
}

MDIO::FrameData::FrameData()
	: m_sharememory("QSharedMemory__CTP_FrameData")
	, m_sysSemaphore("sysSemaphore__CTP_FrameData", 1)
{
	//m_frameDataDir = Tools::GetWorkSpace();
	//if (m_frameDataDir.back() == '/')
	//{
	//	m_frameDataDir += "FrameData/";
	//}
	//else
	//{
	//	m_frameDataDir += "/FrameData/";
	//}

}

bool MDIO::FrameData::Save(std::list<FData::FrameKItem> &pList/*, const KIndexType &msTimeStamp*/)
{
	//std::cout << "输出行情：" << msTimeStamp << std::endl;
	std::vector<FData::FrameKItem> frameDataVec;
	if (!pList.empty())
	{
		frameDataVec.resize(pList.size());
		int dataIndex = 0;
		for (std::list<FData::FrameKItem>::iterator it = pList.begin(); it != pList.end(); ++it, ++dataIndex)
		{
			frameDataVec.at(dataIndex) = *it;
		}
	}
	{
		SystemSemaphoreGard semaphoreGard(m_sysSemaphore);
		m_sharememory.attach();
		if (m_sharememory.isAttached()) {
			if (!m_sharememory.detach()) {
				std::cout << "can't detach" << std::endl;
				return false;
			}
		}
		int size = (int)frameDataVec.size() * sizeof(FData::FrameKItem);
		if (!m_sharememory.create(size)) {
			std::cout << "can't create memory size:" << size << std::endl;
			return false;
		}
		{
			// 内存复制
			ShareMemoryGard pgard(m_sharememory);
			memcpy(m_sharememory.data(), frameDataVec.data(), size);
		}
	}
	return true;
}

bool MDIO::FrameData::Get(std::list<FData::FrameKItem> &outList/*, std::string &fileName*/)
{
	//std::vector<FData::FrameKItem> frameDataVec;
	FData::FrameKItem *frameDataVec = nullptr;
	int ksize = 0;
	{
		SystemSemaphoreGard semaphoreGard(m_sysSemaphore);
		if (m_sharememory.attach())
		{
			{
				ShareMemoryGard pgard(m_sharememory);
				if (m_sharememory.size() > 0)
				{
					ksize = m_sharememory.size() / sizeof(FData::FrameKItem);
					//frameDataVec.resize(m_sharememory.size() / sizeof(FData::FrameKItem));
					frameDataVec = new FData::FrameKItem[ksize];
					memcpy(frameDataVec, m_sharememory.constData(), ksize * sizeof(FData::FrameKItem));
				}
			}
			m_sharememory.detach();
		}
		else
		{
			return false;
		}
	}
	for (int i = 0; i < ksize; ++i)
	{
		outList.emplace_back(frameDataVec[i]);
	}
	if (frameDataVec != nullptr)
	{
		delete[]frameDataVec;
	}
	return true;
}

void MDIO::FrameData::ReleaseData()
{
	SystemSemaphoreGard semaphoreGard(m_sysSemaphore);
	if (m_sharememory.isAttached()) {
		if (!m_sharememory.detach()) {
			std::cout << "can't detach" << std::endl;
		}
	}
}
